﻿using CPN.PJN.Silverlight.Extensions.Validation;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CPN.PJN.Extensions.Validation.UnitTests
{
    [TestClass]
    public class ValidationUnitTests
    {
        public int Property1 { get; set; }

        public string Property2 { get; set; }
        
        [TestInitialize]
        public void Initialize()
        {
            this.Property1 = default(int);
            this.Property2 = default(string);
        }

        [TestMethod]
        [Description("Test de base pour vérifier qu'un nouveau ValidationManager ne contient pas d'erreur")]
        public void UnitTest1_ValidationManagerHasNoError()
        {
            var validationManager = new ValidationManager();
            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);
        }

        [TestMethod]
        [Description("Vérifie que la validation d'une propriété non enregistrée ne génère pas d'erreur")]
        public void UnitTest2_NoErrorIfNoExistingProperty()
        {
            var validationManager = new ValidationManager();

            validationManager.ValidateRules(() => this.Property1);

            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);
        }

        [TestMethod]
        [Description("Teste si une validation sans passer par les règles fonctionne")]
        public void UnitTest3_ValidateTest()
        {
            var validationManager = new ValidationManager();

            validationManager.Validate(() => this.Property1, false, "Oops, erreur !");

            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);
            Assert.AreEqual("Oops, erreur !", validationManager.GetError("Property1"));
        }

        [TestMethod]
        [Description("Teste si une validation appelle bien la méthode pour soulever un événement ErrorsChanged")]
        public void UnitTest4_RaiseErrorsChanged()
        {
            var validationManager = new ValidationManager((propertyName) =>
            {
                Assert.AreEqual(propertyName, "Property1");
            });

            validationManager.Validate(() => this.Property1, false, "Oops, erreur !");
        }

        [TestMethod]
        [Description("Teste le comportement du RequiredValidator")]
        public void UnitTest5_RequiredValidator()
        {
            var validationManager = new ValidationManager();

            validationManager.SetRuleFor(() => this.Property1, new RequiredValidator<int>(), "Champ requis !");

            validationManager.ValidateRules(() => this.Property1);
            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);
            Assert.AreEqual("Champ requis !", validationManager.GetError("Property1"));

            this.Property1 = 42;
            validationManager.ValidateRules(() => this.Property1);
            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);
        }

        [TestMethod]
        [Description("Teste le comportement du RequiredStringValidator")]
        public void UnitTest6_RequiredStringValidator()
        {
            var validationManager = new ValidationManager();

            validationManager.SetRuleFor(() => this.Property2, new RequiredStringValidator(), "Champ requis !");

            // Null
            this.Property2 = null;
            validationManager.ValidateRules(() => this.Property2);
            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);
            Assert.AreEqual("Champ requis !", validationManager.GetError("Property2"));
            
            // Empty
            this.Property2 = string.Empty;
            validationManager.ValidateRules(() => this.Property2);
            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);
            Assert.AreEqual("Champ requis !", validationManager.GetError("Property2"));

            // Ni null ni empty
            this.Property2 = "Pouet";
            validationManager.ValidateRules(() => this.Property2);
            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);
        }

        [TestMethod]
        [Description("Teste le comportement du MailValidator")]
        public void UnitTest7_MailValidator()
        {
            var validationManager = new ValidationManager();

            validationManager.SetRuleFor(() => this.Property2, new MailValidator(), "Champ mal formatté !");

            validationManager.ValidateRules(() => this.Property2);
            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);

            this.Property2 = "Pouet";
            validationManager.ValidateRules(() => this.Property2);
            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);

            this.Property2 = "Pouet@pouet";
            validationManager.ValidateRules(() => this.Property2);
            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);

            this.Property2 = "Pouet@pouet.com";
            validationManager.ValidateRules(() => this.Property2);
            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);
        }

        [TestMethod]
        [Description("Teste le comportement du CustomValidator")]
        public void UnitTest8_CustomValidator()
        {
            var validationManager = new ValidationManager();

            validationManager.SetRuleFor(() => this.Property2, new CustomValidator<string>((s) => s == "Test"), "Champ mal formatté !");

            this.Property2 = "Hihi";
            validationManager.ValidateRules(() => this.Property2);
            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);

            this.Property2 = "Test";
            validationManager.ValidateRules(() => this.Property2);
            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);
        }

        [TestMethod]
        [Description("Teste le comportement du RangeValidator")]
        public void UnitTest9_RangeValidator()
        {
            var validationManager = new ValidationManager();

            validationManager.SetRuleFor(() => this.Property1, new RangeValidator<int>(42, 51), "Champ mal formatté !");

            this.Property1 = 3;
            validationManager.ValidateRules(() => this.Property1);
            Assert.IsTrue(validationManager.HasErrors);
            Assert.AreEqual(1, validationManager.ErrorsCount);

            this.Property1 = 42;
            validationManager.ValidateRules(() => this.Property1);
            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);

            this.Property1 = 51;
            validationManager.ValidateRules(() => this.Property1);
            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);

            this.Property1 = 45;
            validationManager.ValidateRules(() => this.Property1);
            Assert.IsFalse(validationManager.HasErrors);
            Assert.AreEqual(0, validationManager.ErrorsCount);
        }
    }
}